/*
 ============================================================================
 Name        : bit_lib.c
 Author      : felven
 Version     :
 Copyright   : Your copyright notice
 Description : Hello World in C, Ansi-style
 ============================================================================
 */

#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/ioctl.h>
#include <linux/if.h>
#include <string.h>
#include <ifaddrs.h>

#include "bit_lib.h"

int iSockFd = -1;
struct sockaddr_in st_addrSend;
struct sockaddr_in anyaddr;
struct in_addr addr;
struct ip_mreq   mcast;

char ip[64];

//IP_MULTICAST_IF
//IP_ADD_MEMBERSHIP

int udpParseAddress(char * addr, struct sockaddr_in * addr_in)
{
	addr_in->sin_family = AF_INET;
	if(addr == NULL)
	{
		addr_in->sin_addr.s_addr = htonl(INADDR_ANY);
	}
	else
	{
		if(((addr_in->sin_addr).s_addr=(in_addr_t)inet_addr(addr)) == ((in_addr_t)0)) return -1;
	}
	return 0;
}


int get_ip(char *name,char *ip)
{
	struct ifaddrs *ifAddrStruct;
	void *tmpAddrPtr=NULL;
	getifaddrs(&ifAddrStruct);
	while (ifAddrStruct != NULL)
	{
		if ((strcmp(ifAddrStruct->ifa_name,name)==0)&&(ifAddrStruct->ifa_addr->sa_family==AF_INET))
		{
			tmpAddrPtr=&((struct sockaddr_in *)ifAddrStruct->ifa_addr)->sin_addr;
			inet_ntop(AF_INET, tmpAddrPtr, ip, INET_ADDRSTRLEN);
			printf("%s IP Address:%s\n", ifAddrStruct->ifa_name, ip);
		}
		ifAddrStruct=ifAddrStruct->ifa_next;
	}
	freeifaddrs(ifAddrStruct);
	return 0;
}

int net_detect(char* net_name)
{
	int skfd = 0;
	struct ifreq ifr;
	skfd = socket(AF_INET, SOCK_DGRAM, 0);
	if(skfd < 0)
	{
		printf("%s:%d Open socket error!\n", __FILE__, __LINE__);
		return -1;
	}
	strcpy(ifr.ifr_name, net_name);

	if(ioctl(skfd, SIOCGIFFLAGS, &ifr) <0 )
	{
		printf("%s:%d IOCTL error!\n", __FILE__, __LINE__);
		printf("Maybe ethernet inferface %s is not valid!", ifr.ifr_name);
		close(skfd);
		return -1;
	}
	if(ifr.ifr_flags & IFF_RUNNING)
	{
		return 1;
	}
	else
	{
		return -1;
	}
}

int get_available_ip()
{
	if(net_detect("enp9s0f2")==1)
	{
		get_ip("enp9s0f2",ip);
		return 1;
	}
	else if(net_detect("enp9s0f3")==1)
	{
		get_ip("enp9s0f3",ip);
		return 1;
	}
	else if(net_detect("enp7s0")==1)
	{
		get_ip("enp7s0",ip);
		return 1;
	}
	else
	{
		printf("Error! no available network\n");
		return -1;
	}
}

int createSocket()
{
	if(get_available_ip()==-1)
	{
		printf("create socket failed:no available link-up netcard\n");
		return -1;
	}
	else
	{
		bzero((char *)&st_addrSend, sizeof(st_addrSend));
		bzero((char *)&addr, sizeof(addr));
		int socklen = sizeof(struct sockaddr_in);
		iSockFd = socket(AF_INET, SOCK_DGRAM, 0);
		if (iSockFd < 0)
		{
			printf("ERROR:Socket create error!!\n");
			return -1;
		}
		udpParseAddress(ip,&anyaddr);
		anyaddr.sin_port = htons(UDP_RECV_PORT);
		if(bind(iSockFd,(struct sockaddr *)&anyaddr,socklen)<0)
		{
			printf("udpCreateSocket: fail to bind to localaddr\n");
			close(iSockFd);
			return -1;
		}

		st_addrSend.sin_family = AF_INET;
		st_addrSend.sin_port = htons(UDP_SEND_PORT);
		st_addrSend.sin_addr.s_addr = inet_addr(UDP_MULTI_GROUP);
		mcast.imr_multiaddr.s_addr=inet_addr(UDP_MULTI_RECV_GROUP);
		mcast.imr_interface.s_addr = inet_addr(ip);
		if(setsockopt(iSockFd, IPPROTO_IP, IP_MULTICAST_IF, (char *)&mcast, sizeof(mcast))<0)
		{
			printf("setsocket error\n");
			return -1;
		}
		if(setsockopt(iSockFd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&mcast, sizeof(mcast))<0)
		{
			printf("setsocket error\n");
			return -1;
		}
		return 1;
	}
}


int udpSend()
{

	if(sendto(iSockFd, g_bitInfo, 32, 0, (struct sockaddr *)&st_addrSend, sizeof(struct sockaddr_in))<0)
	{
		printf("send BIT Info Fail\n");
	}
	else
	{
		printf("send BIT Info Success\n");
	}
	return 0;
}

int udpRecv()
{
	char buffer[65536];
	int peerlen = sizeof(struct sockaddr_in);
	struct sockaddr_in peeraddr_recv;
	printf("recv BIT Info\n");
	while(1)
	{
		recvfrom(iSockFd,buffer,65536,0,(struct sockaddr *)&(peeraddr_recv),&peerlen);
		printf("recv data is %s\n",buffer);
	}
	return 1;
}

